Interactive cluster map and timeline of GPS data
Recently heard about the Parler web scrape that happened a few days ago. It was awesome to read about the archiving work that @donk_enby led (link to her Twitter page).
Found the processed metadata on Github yesterday evening. Thanks to zumbov2 on Github for his repo and data export. Got to work after I had the data. Thought it would be cool to see in Leaflet, combined with leaftime for timelines in Leaflet.
The raw data source I used had 64,399 records with GPS coordinates from 2011-08-11 to 2021-01-10. Had creation date, latitude, and longitude fields to work with. The count I read across multiple articles was 68K, but there are ~5% of records with missing or bad coordinates. Checked full data that Kyle Mcdonald posted and found obtained same record count after filtering out for records long/lat at origin (0,0).
Note that the data represents only content that was publicly available, as pointed out by donk_enby on her Vice article and this Wired article.
The first map is a cluster map focused on Washington DC on January 6, 2020. Second is a timeline looks at the data from November 1, 2020 onward (US election occurred on Tuesday, November 3). Feel free to interact with the maps as you like. This was a great opportunity for me to learn more about Leaflet. Code included below maps.
parler_all <- read_csv("https://raw.githubusercontent.com/zumbov2/parler-video-metadata/main/parler_vids_geolocation_time.csv")
dt2 <- parler_all %>%
mutate(CreateDate = ymd_hms(CreateDate)) %>%
mutate(start = as_date(CreateDate), end = as_date(CreateDate)+1) %>%
filter(start > as_date("2020-11-01"))
#dt2 parler video data time lapse
dt2_geo <- geojsonio::geojson_json(dt2)
#on 2021-6-1
dt2_jan6 <- dt2 %>%
filter(date(CreateDate) == "2021-01-06")
# filter(lat > 38.6 & lat < 39.2)
tag.map.title_white <- tags$style(HTML("
.leaflet-control.map-title-white {
position: sticky !important;
left: 25%;
right: 50%;
text-align: center;
font-weight: bold;
font-size: 18px;
color: WhiteSmoke;
}
"))
title <- tags$div(
tag.map.title_white, HTML("Parler Metadata on Jan 6, 2020")
)
tag.map.title_black <- tags$style(HTML("
.leaflet-control.map-title-black {
position: sticky !important;
left: 25%;
right: 50%;
text-align: center;
font-weight: bold;
font-size: 18px;
color: black;
}
"))
title2 <- tags$div(
tag.map.title_black, HTML("Parler Metadata over Time")
)
# Leaflet map1
leaflet(dt2_jan6) %>%
addControl(title, position = "topright", className="map-title-white") %>%
setView(lng = -77.025, lat = 38.892, zoom = 12) %>%
addProviderTiles(providers$Esri.NatGeoWorldMap) %>%
addCircleMarkers(
color = "red", radius=7,
stroke = FALSE, fillOpacity = 0.7,
popup = ~paste(as.character(CreateDate),"at (", as.character(lat), as.character(lon),")"),
labelOptions = labelOptions(style = list("font-size" = "8px")),
clusterOptions = markerClusterOptions(), clusterId = "quakesCluster"
) %>%
addMiniMap(
tiles = providers$Esri.WorldStreetMap,
toggleDisplay = TRUE) %>%
addEasyButton(easyButton(
states = list(
easyButtonState(
stateName="unfrozen-markers",
icon="ion-toggle",
title="Freeze Clusters",
onClick = JS("
function(btn, map) {
var clusterManager =
map.layerManager.getLayer('cluster', 'quakesCluster');
clusterManager.freezeAtZoom();
btn.state('frozen-markers');
}")
),
easyButtonState(
stateName="frozen-markers",
icon="ion-toggle-filled",
title="UnFreeze Clusters",
onClick = JS("
function(btn, map) {
var clusterManager =
map.layerManager.getLayer('cluster', 'quakesCluster');
clusterManager.unfreeze();
btn.state('unfrozen-markers');
}")))))
#Leaflet map2
leaflet(dt2_geo, options = leafletOptions(zoomControl = TRUE,
dragging = TRUE,
preferCanvas = FALSE)) %>%
addTiles() %>%
addControl(title2, position = "topright", className="map-title-black") %>%
setView(lng = -77.025, lat = 38.892, zoom = 6) %>%
addTimeline(
width = "40%",
sliderOpts = sliderOptions(
formatOutput = htmlwidgets::JS("function(StartDate) {return new Date(StartDate).toDateString()}"),
steps=length(unique(dt2$start)),
position = "bottomright",
duration = 150000,
showTicks = TRUE,
enablePlayback = TRUE,
enableKeyboardControls = TRUE,
waitToUpdateMap = FALSE),
timelineOpts = timelineOptions(
styleOptions = styleOptions(
color = "red",
fillOpacity = 0.5,
radius = 2))
) %>%
addEasyButton(easyButton(icon="fa-crosshairs", title="Locate Me",
onClick=JS("function(btn, map){ map.locate({setView: true}); }"))) %>%
addEasyButton(easyButton(icon="fa-globe", title="Zoom to Level 1",
onClick=JS("function(btn, map){ map.setZoom(1); }")))
If you see mistakes or want to suggest changes, please create an issue on the source repository.
For attribution, please cite this work as
Parmar (2021, Jan. 16). Data Breadcrumbs: Parler Metadata in Leaflet. Retrieved from https://databreadcrumbs.com/posts/2021-01-16-parler-metadata/
BibTeX citation
@misc{parmar2021parler,
author = {Parmar, Sam},
title = {Data Breadcrumbs: Parler Metadata in Leaflet},
url = {https://databreadcrumbs.com/posts/2021-01-16-parler-metadata/},
year = {2021}
}